package com.terracloud.server.service.entitiy.tenant.group;

import com.terracloud.server.common.data.IdName;
import com.terracloud.server.common.data.TenantGroup;
import com.terracloud.server.common.data.audit.ActionType;
import com.terracloud.server.common.data.id.TenantGroupId;
import com.terracloud.server.common.data.id.TenantId;
import com.terracloud.server.common.data.page.PageData;
import com.terracloud.server.common.data.page.PageLink;
import com.terracloud.server.dao.model.sql.TenantEntity;
import com.terracloud.server.dao.model.sql.TenantGroupEntity;
import com.terracloud.server.dao.model.sql.TenantGroupRelationEntity;
import com.terracloud.server.dao.sql.tenant.TenantGroupRelationRepository;
import com.terracloud.server.dao.sql.tenant.TenantGroupRepository;
import com.terracloud.server.dao.sql.tenant.TenantRepository;
import com.terracloud.server.dao.tenant.TenantDao;
import com.terracloud.server.queue.util.TbCoreComponent;
import com.terracloud.server.service.entitiy.AbstractTbEntityService;
import com.terracloud.server.service.security.model.SecurityUser;
import com.terracloud.server.utils.PageDataUtils;
import com.terracloud.server.vo.TenantGroupRelationUpdateVo;
import jakarta.persistence.criteria.Predicate;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 * @author chenhainan
 * @since 2025/10/11
 */
@AllArgsConstructor
@TbCoreComponent
@Service
@Slf4j
public class DefaultTbTenantGroupService extends AbstractTbEntityService implements TbTenantGroupService {

    private final TenantGroupRepository tenantGroupRepository;

    private final TenantGroupRelationRepository tenantGroupRelationRepository;

    private final TenantRepository tenantRepository;

    private final TenantDao tenantDao;

    private final JdbcTemplate jdbcTemplate;


    @Override
    public TenantGroup saveTenantGroup(TenantGroup tenantGroup, SecurityUser currentUser) {
        ActionType actionType = tenantGroup.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
        TenantGroupEntity tenantGroupEntity = new TenantGroupEntity(tenantGroup);
        if (actionType == ActionType.ADDED) {
            tenantGroupEntity.setCreatedTime(System.currentTimeMillis());
        }
        tenantGroupRepository.save(tenantGroupEntity);
        tenantGroup.setId(new TenantGroupId(tenantGroupEntity.getId()));
        autoCommit(currentUser, tenantGroup.getId());
        logEntityActionService.logEntityAction(currentUser.getTenantId(), tenantGroup.getId(), tenantGroup, actionType, currentUser);
        return tenantGroup;
    }

    @Override
    public TenantGroup findTenantGroupById(TenantId tenantId, TenantGroupId tenantGroupId) {
        return tenantGroupRepository.findById(tenantGroupId.getId()).map(TenantGroupEntity::toData).orElse(null);
    }

    @Override
    public TenantGroup findTenantGroupInfoById(TenantId tenantId, TenantGroupId id) {
        final var tenantGroup = findTenantGroupById(tenantId, id);
        if (tenantGroup == null) {
            return null;
        }
        final var tenantIds = tenantGroupRelationRepository.findAllByTenantGroupId(tenantGroup.getUuidId()).stream()
                .map(TenantGroupRelationEntity::getTenantId)
                .toList();
        if (tenantIds.isEmpty()) {
            tenantGroup.setTenants(Collections.emptyList());
        } else {
            final var tenantGroupTenantInfoList = tenantRepository.findAllById(tenantIds)
                    .stream().map(TenantEntity::toData).toList();
            tenantGroup.setTenants(tenantGroupTenantInfoList);
        }
        tenantGroup.setTenantCount((long) tenantIds.size());
        return tenantGroup;
    }

    @Override
    @Transactional
    public void delete(TenantGroup tenantGroup, SecurityUser currentUser) {
        tenantGroupRepository.deleteById(tenantGroup.getUuidId());
        tenantGroupRelationRepository.deleteByTenantGroupId(tenantGroup.getUuidId());
        logEntityActionService.logEntityAction(tenantGroup.getTenantId(), tenantGroup.getId(), tenantGroup, ActionType.DELETED, currentUser);

    }

    @Override
    public PageData<TenantGroup> findTenantGroups(TenantId tenantId, PageLink pageLink) {
        Specification<TenantGroupEntity> condition = (root, query, builder) -> {
            List<Predicate> conditions = new ArrayList<>();
            conditions.add(builder.equal(root.get("tenantId"), tenantId.getId()));
            if (StringUtils.hasText(pageLink.getTextSearch())) {
                conditions.add(builder.like(root.get("name"), '%' + pageLink.getTextSearch() + '%'));
            }
            return builder.and(conditions.toArray(new Predicate[0]));
        };
        try {
            return PageDataUtils.toPageDataAsync(tenantGroupRepository.findAll(condition, PageRequest.of(pageLink.getPage(), pageLink.getPageSize())),
                    tenantGroupEntity -> {
                        final var tenantGroup = tenantGroupEntity.toData();
                        tenantGroup.setTenantCount(tenantGroupRelationRepository.countByTenantGroupId(tenantGroupEntity.getId()));
                        return tenantGroup;
                    });
        } catch (Exception e) {
            log.error("查询设备分组发生异常", e);
            return new PageData<>();
        }
    }

    @Override
    public void addTenantToGroup(SecurityUser currentUser, TenantGroupRelationUpdateVo tenantGroupRelationUpdateVo) {
        final var existTenantIds = tenantGroupRelationRepository.findAllByTenantGroupId(tenantGroupRelationUpdateVo.getTenantGroupId())
                .stream().map(TenantGroupRelationEntity::getTenantId).collect(Collectors.toSet());
        final var groupRelationEntityList = tenantGroupRelationUpdateVo.getTenantIds().stream().filter(tenantId -> !existTenantIds.contains(tenantId))
                .map(tenantId -> {
                    final var tenantGroupRelationEntity = new TenantGroupRelationEntity(tenantId, tenantGroupRelationUpdateVo.getTenantGroupId());
                    tenantGroupRelationEntity.setCreatedTime(System.currentTimeMillis());
                    return tenantGroupRelationEntity;
                }).toList();
        tenantGroupRelationRepository.saveAll(groupRelationEntityList);
    }


    @Override
    @Transactional
    public void removeTenantFromGroup(SecurityUser currentUser, TenantGroupRelationUpdateVo tenantGroupRelationUpdateVo) {
        tenantGroupRelationRepository.removeAllByTenantGroupIdIsAndTenantIdIn(tenantGroupRelationUpdateVo.getTenantGroupId(), tenantGroupRelationUpdateVo.getTenantIds());
    }
}
